package com.itheima.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.stock.common.domain.*;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.vo.req.PageResult;
import com.itheima.stock.vo.res.R;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;


//定义股票服务接口实现
@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    //查询所有主营业务信息
    @Override
    public List<StockBusiness> findAll() {
        return stockBusinessMapper.getAll();
    }


    //获取最新的国内大盘参数
    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfos() {
        //1.获取最近最新一次的股票交易时间
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //todo mock data 后期删除
        curDateTime = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据指定时间点和对应大盘id查询对应信息
        List<InnerMarketDomain> infos = stockMarketIndexInfoMapper.findMarketInfoByTimeAndCodes(curDateTime,stockInfoConfig.getInner());
        return R.ok(infos);
    }

    //查询最近最近的版块数据信息
    @Override
    public R<List<StockBlockDomain>> getStockBlockInfo() {
        //1.获取最近最新一次的股票交易时间
        Date curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //todo mock data 后期删除
        curDateTime = DateTime.parse("2022-01-14 16:57:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据时间查询对应大盘数据信息
        List<StockBlockDomain> infos = stockBlockRtInfoMapper.findBlockInfoByTimeLimit(curDateTime);
        //3.响应
        return R.ok(infos);
    }

    //统计A股 最新交易数据 并按涨幅取前10
    @Override
    public R<List<StockUpdownDomain>> getStockInfoByIncrease() {
        //1.获取最新 股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO 假数据 mockdata
        curDate = DateTime.parse("2022-03-21 14:33:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper根据时间点 获取股票数据
        List<StockUpdownDomain> infos = stockRtInfoMapper.getStockInfoByIncrease(curDate);
        //3.返回结果
        return R.ok(infos);
    }

    //分页查询股票数据
    @Override
    public R<PageResult<StockUpdownDomain>> getStockByPage(Integer page, Integer pageSize) {
        //1.设置分页参数 底层自动为当前执行查询的sql添加limit语句 实现分页
        PageHelper.startPage(page, pageSize);
        //2.查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getStockAll();
        //3.构建分页详情对象
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(infos);
        //4.转化成自定义的分页数据 目的是精简数据
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        //返回数据
        return R.ok(pageResult);
    }

    //统计T日没分钟 涨停跌停数据
    @Override
    public R<Map> getStockUpdownCount() {
        //1.获取最近有效的交易时间点
        DateTime newDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //获取截止日期时间点
        Date endTime = newDateTime.toDate();
        //获取endTime对应 开盘时间，就是开始时间
        Date startTime = DateTimeUtil.getOpenDate(newDateTime).toDate();
        //TODO MOCKDATA 伪数据
        endTime = DateTime.parse("2022-01-06 14:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        startTime = DateTime.parse("2022-01-06 09:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.根据时间范围获取 对应的涨跌停数 约定：flag 1：涨停 0：跌停
        //2.1 获取涨停数
        List<Map> upList = stockRtInfoMapper.getStockUpdownCount(startTime,endTime,1);
        //2.1 获取跌停 统计数据
        List<Map> downList = stockRtInfoMapper.getStockUpdownCount(startTime,endTime,0);

        //3.组装数据 响应前端
        Map<String, List> mapInfo = new HashMap<>();
        mapInfo.put("upList", upList);
        mapInfo.put("downList", downList);
        //返回
        return R.ok(mapInfo);
    }

    //股票数据导出到Excel中
    @Override
    public void exportStockInf4Excel(HttpServletResponse response, Integer page, Integer pageSize) {
        try {
            //1.设置响应数据的类型:excel
            response.setContentType("application/vnd.ms-excel");
            //2.设置响应数据的编码格式
            response.setCharacterEncoding("utf-8");
            //3.设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            //设置默认文件名称
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //4.获取分页数据
            PageHelper.startPage(page, pageSize);
            List<StockUpdownDomain> infos = stockRtInfoMapper.getStockAll();
            //5.给前端响应数据
            EasyExcel.write(response.getOutputStream(),StockUpdownDomain.class).sheet("股票数据")
                    .doWrite(infos);
        } catch (IOException e) {
            log.info("导出数据异常:{}",e.getMessage());
        }
    }


    //通过T日和T-1日大盘成交量对比数据
    @Override
    public R<Map<String, List>> getStockCompareTradeVol() {
        //1.1获取最新的一次股票交易时间点
        DateTime tDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date tEndTime = tDateTime.toDate();
        //1.2获取T日的开盘时间
        Date tStartTime = DateTimeUtil.getOpenDate(tDateTime).toDate();
        //2.1获取T-1日对应的截止时间，保证与T日时间线对齐
        DateTime preTDateTime = DateTimeUtil.getPreviousTradingDay(tDateTime);
        Date preTEndTime = preTDateTime.toDate();
        //2.2获取上个交易日的开盘时间
        Date preTStartTime = DateTimeUtil.getOpenDate(preTDateTime).toDate();
        //TODO MOCK DATA
        tEndTime = DateTime.parse("2022-01-03 14:40:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        tStartTime = DateTime.parse("2022-01-03 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        preTEndTime = DateTime.parse("2022-01-02 14:40:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        preTStartTime = DateTime.parse("2022-01-02 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // \TODO MOCK DATA

        //3.调用mapper接口获取数据
        //3.1获取T日成交量数据
        List<Map> tData = stockMarketIndexInfoMapper.getTradeVolInfoByTime(stockInfoConfig.getInner(), tStartTime, tEndTime);
        //3.2获取T-1日成交量数据
        List<Map> preTData = stockMarketIndexInfoMapper.getTradeVolInfoByTime(stockInfoConfig.getInner(), preTStartTime, preTEndTime);
        //4.组装数据
        Map<String, List> data = new HashMap<>();
        data.put("volList", tData);
        data.put("yesVolList", preTData);
        //5.返回响应的数据
        return R.ok(data);
    }

    //统计当前时间下（精确到分钟），股票在各个涨幅区间的数量
    @Override
    public R<Map> getStockUpDwonScopeNum() {
        //1.获取当前最新的股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //todo mock data
        curDate = DateTime.parse("2022-01-06 09:55:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // \todo mock data
        //2.根据指定时间点查询涨幅区间数量
        List<Map> rangeInfo = stockRtInfoMapper.getLastDate4Stock(curDate);
        //2.1 补充 1.补齐残缺范围没有数据问题 2.将title标题合理排序在前端展示
//        ArrayList<Map> maps = new ArrayList<>();
//        for (String title : stockInfoConfig.getUpDownRange()) {
//            Map tmp = null;
//            for (Map map : rangeInfo) {
//                if (map.get("title").equals(title)) {
//                    tmp = map;
//                    break;
//                }
//            }
//            if (tmp == null) {
//                tmp = new HashMap();
//                tmp.put("title",title);
//                tmp.put("count",0);
//            }
//            maps.add(tmp);
//        }
        //方式2：用lambda表达式实现stream
        List<Map> maps = stockInfoConfig.getUpDownRange().stream().map(title->{
            Optional<Map> optional = rangeInfo.stream().filter(map -> title.equals(map.get("title"))).findFirst();
            Map map = null;
            if (optional.isPresent()) {
                map = optional.get();
            } else {
                map = new HashMap();
                map.put("title", title);
                map.put("count", 0);
            }
            return map;
        }).collect(Collectors.toList());

        //3.组装数据
        Map data = new HashMap();
        String curStrDate = new DateTime(curDate).toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm"));
        data.put("time",curStrDate);
//        data.put("infos",rangeInfo);
        data.put("infos",maps);

        //4.响应数据
        return R.ok(data);

    }

    //查询股票分时数据
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        //1.获取最新的股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //截止时间
        Date endTime = curDateTime.toDate();
        //开盘时间
        Date startTime = DateTimeUtil.getOpenDate(curDateTime).toDate();
        //todo mock data
        endTime = DateTime.parse("2021-12-30 14:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        startTime = DateTime.parse("2021-12-30 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // \todo mock data
        //2.查询数据
        List<Stock4MinuteDomain> data = stockRtInfoMapper.getStockScreenTimeSharing(stockCode, startTime, endTime);
        //返回数据
        return R.ok(data);
    }

    //查询股票日k线信息
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDayKLine(String stockCode) {
        //1.获取最新的股票交易时间点
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endDate = endDateTime.toDate();
        //向后推n天
        DateTime startDateTime = DateTimeUtil.getOpenDate(endDateTime.minusDays(10));
        Date startDate = startDateTime.toDate();
        //todo mock data
        endDate = DateTime.parse("2022-01-06 14:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        startDate = DateTime.parse("2022-01-01 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        // \todo mock data
        //2.查询股票日k线信息
        List<Stock4EvrDayDomain> infos = stockRtInfoMapper.getStockScreenDayKLine(stockCode,startDate,endDate);
        return R.ok(infos);
    }
}
